package com.bestcem.xm.label.service.impl;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.bestcem.xm.common.core.constant.ErrorCodes;
import com.bestcem.xm.common.core.domain.web.ServiceResult;
import com.bestcem.xm.common.core.exception.BaseRuntimeException;
import com.bestcem.xm.common.core.sql.*;
import com.bestcem.xm.common.core.sql.calculator.ConditionCalculator;
import com.bestcem.xm.common.core.sql.calculator.ConditionCalculatorFactory;
import com.bestcem.xm.common.core.uitls.EnumUtil;
import com.bestcem.xm.common.core.uitls.IdUtil;
import com.bestcem.xm.common.core.uitls.JsonUtil;
import com.bestcem.xm.label.autolabel.LabelMemberContext;
import com.bestcem.xm.label.config.LabelAppConfig;
import com.bestcem.xm.label.constant.Constants;
import com.bestcem.xm.label.dao.LabelDao;
import com.bestcem.xm.label.dao.LabelValueDao;
import com.bestcem.xm.label.entity.pojo.LabelValueDO;
import com.bestcem.xm.label.enums.ConditionCategoryEnum;
import com.bestcem.xm.label.enums.ConditionVersionEnum;
import com.bestcem.xm.label.enums.MatchEnum;
import com.bestcem.xm.label.grpc.service.param.LabelMembersParam;
import com.bestcem.xm.label.grpc.service.param.LabelValueIdParam;
import com.bestcem.xm.label.grpc.service.param.MemberParam;
import com.bestcem.xm.label.service.LabelMemberService;
import com.bestcem.xm.label.service.dto.LabelValueDTO;
import com.bestcem.xm.label.service.dto.SurveyConditionDTO;
import com.bestcem.xm.member.config.PerformanceConfig;
import com.bestcem.xm.member.dao.MemberDao;
import com.bestcem.xm.member.enums.SurveyProjectStatusEnum;
import com.bestcem.xm.member.grpc.client.SurveyClient;
import com.bestcem.xm.member.grpc.client.UserClient;
import com.bestcem.xm.member.grpc.client.XmQdesClient;
import com.bestcem.xm.member.grpc.client.dto.CompileConditionDTO;
import com.bestcem.xm.member.grpc.client.dto.ExecuteConditionDTO;
import com.bestcem.xm.member.grpc.client.dto.QdesProjectDTO;
import com.bestcem.xm.member.grpc.client.params.CompileConditionParam;
import com.bestcem.xm.member.grpc.client.params.ExecuteConditionParam;
import com.bestcem.xm.member.service.GroupService;
import com.bestcem.xm.member.service.MemberUserGroupService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.bson.types.ObjectId;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author ming.xue <ming.xue@idiaoyan.com>
 * @desc 自动打标签服务
 * @date 2021-05-18
 */
@Slf4j
@Service("labelMemberService")
public class LabelMemberServiceImpl implements LabelMemberService {

    private static final Logger MEMBER_PERFORMANCE_LOG = LoggerFactory.getLogger("MemberPerformanceLog");
    /**
     * 标签
     */
    @Autowired
    private LabelDao labelDao;

    /**
     * 标签值
     */
    @Autowired
    private LabelValueDao labelValueDao;

    @Resource
    private GroupService groupService;

    /**
     * 答卷服务
     */
    @Autowired
    private SurveyClient surveyClient;

    /**
     * 应用配置
     */
    @Autowired
    private LabelAppConfig appConfig;

    /**
     * 自动打标签每批次推送的联系人数目上限，默认1000人
     */
    @Value("${app.label.max-auto-label-batch-size:1000}")
    private int maxAutoLabelBatchSize;

    /**
     * 联系人数据访问层
     */
    @Autowired
    private MemberDao memberDao;

    /**
     * 问卷服务客户端
     */
    @Autowired
    private XmQdesClient qdesClient;

    @Autowired
    private MemberUserGroupService memberUserGroupService;

    private final static Integer REQUEST_SIZE = 300;

    /**
     * 用户客户端
     */
    @Autowired
    private UserClient userClient;

    /**
     * 编译自动条件
     *
     * @param orgId
     * @param condition
     * @return
     */
    @Override
    public <T> ServiceResult<Wrapper<T>> compileCondition(String orgId, String condition) {
        Map<String, ColumnDesc> columnMapping = new HashMap<>(8);
        columnMapping.put("store", ColumnDesc.newInstance("store_id", ColumnDesc.JDBC_TYPE_BINARY));
        return this.compileCondition(orgId, condition, columnMapping, null, Constants.ZERO);
    }

    /**
     * 编译自动条件
     *
     * @param orgId
     * @param condition
     * @param features
     * @return
     */
    @Override
    public <T> ServiceResult<Wrapper<T>> compileCondition(String orgId, String condition, int features) {
        Map<String, ColumnDesc> columnMapping = new HashMap<>(8);
        columnMapping.put("store", ColumnDesc.newInstance("store_id", ColumnDesc.JDBC_TYPE_BINARY));
        return this.compileCondition(orgId, condition, columnMapping, null, features);
    }

    /**
     * 编译动态条件
     * 保存标签值动态条件之前，需要经过编译校验其语法是否正确
     *
     * @param orgId
     * @param condition
     * @return
     */
    @Override
    public <T> ServiceResult<Wrapper<T>> compileCondition(String orgId, String condition,
                                                               Map<String, ColumnDesc> columnMapping, String tableAlias,
                                                               int features) {
        try {
            // 将标签条件解析成JSON
            JSONObject conditionObj = JsonUtil.tryConvertToJSONObject(condition);
            if (conditionObj == null) {
                throw new ConditionException("condition convert to json failed");
            }
            // 归一化动态条件
            this.normalizingCondition(conditionObj);

            // 编译问卷相关条件
            if (!CompileFeature.isEnabled(features, CompileFeature.SKIP_SURVEY_CONDITION)) {
                this.compileSurveyCondition(orgId, conditionObj, features);
            }

            // 编译动态条件
            Wrapper<T> wrapper = this.compileNormalCondition(orgId, conditionObj, columnMapping, tableAlias, features);
            return ServiceResult.success(wrapper);
        } catch (BaseRuntimeException e) {
            log.error("condition compile failed, orgId: {}, errorCode: {}, reason: {}, condition: {}",
                    orgId, e.getCode(), e.getDesc(), condition, e);
            if (StringUtils.equals(e.getCode(), ErrorCodes.A0400)) {
                return ServiceResult.<Wrapper<T>>fail(e.getDesc()).setErrorCode(ErrorCodes.A0400);
            }
        } catch (Exception e) {
            log.error("condition compile failed, reason unknown, orgId: {}, condition: {}", orgId, condition, e);
        }
        return ServiceResult.<Wrapper<T>>fail("条件解析失败").setErrorCode(ErrorCodes.A0400);
    }

    /**
     * 编译问卷相关条件
     *  @param orgId
     * @param conditionObj
     * @param features
     */
    private void compileSurveyCondition(String orgId, JSONObject conditionObj, int features) {
        // 获取问卷项目标识
        String projectId = conditionObj.getString(ConditionConstant.PROJECT_ID);
        if (CompileFeature.isEnabled(features, CompileFeature.CHECK_SURVEY_EXISTS)) {
            this.checkSurveyExists(projectId);
        }

        // 获取问卷相关条件
        List<SurveyConditionDTO> surveyConditions = this.loadSurveyConditions(conditionObj);
        // 准备编译参数
        List<CompileConditionParam> compileConditionParams = surveyConditions.stream().filter(Objects::nonNull)
                .map(surveyCondition -> {
                    CompileConditionParam compileConditionParam = new CompileConditionParam();
                    compileConditionParam.setOrgId(orgId);
                    compileConditionParam.setConditionId(surveyCondition.getConditionId());
                    compileConditionParam.setProjectId(surveyCondition.getProjectId());
                    compileConditionParam.setCondition(surveyCondition.getCondition());
                    return compileConditionParam;
                }).collect(Collectors.toList());

        // 编译问卷相关条件
        List<CompileConditionDTO> compileConditionDTOs = surveyClient.compileConditions(orgId, compileConditionParams);
        // 统计未校验通过的问卷条件
        List<String> failedConditionIds = compileConditionDTOs.stream()
                .filter(compileConditionDTO -> !compileConditionDTO.isValid())
                .map(CompileConditionDTO::getConditionId).collect(Collectors.toList());
        // 若存在为编译通过的问卷条件，则抛出异常
        if (!CollectionUtils.isEmpty(failedConditionIds)) {
            log.error("survey condition compile failed, orgId: {}, failedConditionIds: {}, condition: {}", orgId,
                    failedConditionIds, conditionObj);
            throw new ConditionException("survey condition grammar error");
        }
    }

    /**
     * 检查问卷项目是否存在
     *
     * @param projectId
     */
    private void checkSurveyExists(String projectId) {
        if (StringUtils.isBlank(projectId)) {
            return;
        }

        // 获取问卷项目
        ServiceResult<QdesProjectDTO> result = qdesClient.getProject(projectId);
        if (!result.isSuccess()) {
            throw new ConditionException(ErrorCodes.A0400, result.getMsg());
        }

        /**
         * 判断项目是否已经被删除
         */
        QdesProjectDTO project = result.getData();
        if (Objects.equals(project.getStatus(), SurveyProjectStatusEnum.DELETED.getIndex()) ||
                Objects.equals(project.getStatus(), SurveyProjectStatusEnum.DELETED2.getIndex())) {
            throw new ConditionException(ErrorCodes.A0400, "条件中的问卷项目不存在");
        }
    }

    /**
     * 编译动态条件
     * 保存标签值动态条件之前，需要经过编译校验其语法是否正确
     *
     * @param orgId
     * @param conditionObj
     * @param features
     */
    private <T> Wrapper<T> compileNormalCondition(String orgId, JSONObject conditionObj,
                                            Map<String, ColumnDesc> columnMapping, String tableAlias, int features) {
        // 获取当前标签依赖的标签
        Map<String, Set<String>> nestedLabelMap = this.loadNestedLabelMap(null, conditionObj);
        if (!CollectionUtils.isEmpty(nestedLabelMap)) {
            // 校验标签是否存在
            if (CompileFeature.isEnabled(features, CompileFeature.CHECK_LABEL_EXISTS)) {
                this.checkLabelExists(nestedLabelMap);
            }

            // 编译标签依赖
            if (CompileFeature.isEnabled(features, CompileFeature.CHECK_LABEL_DEPENDENCY_DEPTH)) {
                this.compileLabelCondition(orgId, nestedLabelMap.keySet());
            }
        }

        // 检查所属组织是否存在
        this.checkUserGroupExists(orgId, conditionObj);

        ServiceResult<Wrapper<T>> result = SQLConditionCompiler.newInstance(columnMapping, tableAlias).compile(conditionObj);
        if (!result.isSuccess()) {
            throw new ConditionException(result.getErrorCode(), result.getMsg());
        }
        return result.getData();
    }

    /**
     * 检查所属组织是否存在
     *
     * @param orgId
     * @param conditionObj
     */
    private void checkUserGroupExists(String orgId, JSONObject conditionObj) {
        ConditionTraverser traverser = new ConditionTraverser() {
            @Override
            protected void onSimpleCondition(JSONObject simpleCondition, Map<String, Object> contextParams) {
                // 若不是基础信息，直接跳过
                String source = simpleCondition.getString(ConditionConstant.SOURCE);
                if (!StringUtils.equals(source, ConditionConstant.Sources.INFO)) {
                    return;
                }

                // 若不是所属组织，直接跳过
                ConditionProxy conditionProxy = new ConditionProxy(simpleCondition);
                String name = conditionProxy.getName();
                if (!StringUtils.equals(name, "store")) {
                    return;
                }

                // 检查数据类型
                String dataType = conditionProxy.getDataType();
                if (!StringUtils.equals(dataType, ConditionConstant.FieldTypes.LEVEL)) {
                    throw new ConditionException(String.format("condition.dataType %s of member.store illegal",
                            dataType));
                }

                // 检查条件是否合法
                List<Object> values = conditionProxy.listValues();
                if (CollectionUtils.isEmpty(values) || values.size() < 1) {
                    throw new ConditionException(String.format("condition.value %s illegal", values));
                }
                Object endValue = values.get(values.size() - 1);
                if (endValue == null) {
                    String msg = String.format("condition.value missing for level, endValue: %s", endValue);
                    throw new ConditionException(msg);
                }

                Set<Object> storeIds = (Set<Object>) contextParams.get(ConditionConstant.STORE_IDS);
                if (storeIds == null) {
                    storeIds = new LinkedHashSet<>();
                }
                storeIds.add(endValue);
                contextParams.put(ConditionConstant.STORE_IDS, storeIds);
            }
        };
        Map<String, Object> contextParams = new HashMap<>();
        traverser.traverse(conditionObj, contextParams);

        Set<Object> storeIds = (Set<Object>) contextParams.get(ConditionConstant.STORE_IDS);
        if (CollectionUtils.isEmpty(storeIds)) {
            return;
        }

        Map<String, String> userGroupMap = userClient.listGroupMap(orgId, Collections.singletonList(0));
        for (Object storeId : storeIds) {
            if (storeId == null) {
                continue;
            }

            if (!userGroupMap.containsKey(storeId.toString())) {
                throw new ConditionException(ErrorCodes.A0400, "条件不完善");
            }
        }
    }

    /**
     * 校验标签是否存在
     *
     * @param nestedLabelMap
     */
    private void checkLabelExists(Map<String, Set<String>> nestedLabelMap) {
        if (CollectionUtils.isEmpty(nestedLabelMap)) {
            return;
        }

        // 校验标签是否存在
        Set<String> labelIds = nestedLabelMap.keySet();
        if (labelIds.size() > ConditionConstant.MAX_DEPENDENCY_ITEM_LENGTH) {
            throw new ConditionException(ErrorCodes.A0400, "依赖的标签不能超过200个");
        }
        long labelCount = labelDao.countByIds(labelIds);
        if (labelIds.size() > labelCount) {
            throw new ConditionException(ErrorCodes.A0400, "条件不完善");
        }

        // 校验标签值是否存在
        Set<String> labelValueIds = nestedLabelMap.values().stream().filter(Objects::nonNull)
                .flatMap(Set::stream).collect(Collectors.toSet());
        if (labelValueIds.size() > ConditionConstant.MAX_DEPENDENCY_ITEM_LENGTH) {
            throw new ConditionException(ErrorCodes.A0400, "依赖的标签值不能超过200个");
        }
        long labelValueCount = labelValueDao.countByIds(labelValueIds);
        if (labelValueIds.size() > labelValueCount) {
            throw new ConditionException(ErrorCodes.A0400, "条件不完善");
        }
    }

    /**
     * 编译标签条件
     *
     * @param orgId
     * @param labelIds
     */
    private void compileLabelCondition(String orgId, Set<String> labelIds) {
        // 标签标识和名称的映射
        Map<String, String> labelMap = new LinkedHashMap<>();
        labelMap.put(Constants.NEGATIVE_ONE_STR, "当前标签");

        // 将标签依赖关系维护成图
        GraphSorter<String> graph = new GraphSorter<>();
        graph.addVertex(Constants.NEGATIVE_ONE_STR);
        labelIds.forEach(innerLabelId -> graph.addEdge(Constants.NEGATIVE_ONE_STR, innerLabelId));

        String labelId;
        Queue<String> queue = new LinkedList<>();
        labelIds.forEach(queue::offer);
        while ((labelId = queue.poll()) != null) {
            if (labelMap.containsKey(labelId)) {
                continue;
            }

            List<LabelValueDO> labelValues = labelValueDao.listByOrgIdAndLabelIdAndAuto(orgId, labelId, Boolean.TRUE);
            if (CollectionUtils.isEmpty(labelValues)) {
                continue;
            }

            String finalLabelId = labelId;
            Set<String> nestedLabelIds = new LinkedHashSet<>();
            labelValues.forEach(labelValue -> {
                labelMap.putIfAbsent(labelValue.getLabelId(), labelValue.getLabelName());

                JSONObject nestedConditionObj = JsonUtil.tryConvertToJSONObject(labelValue.getCondition());
                if (nestedConditionObj == null) {
                    String msg = String.format("依赖的标签[%s]的标签值[%s]，条件语法错误", labelValue.getLabelName(),
                            labelValue.getValue());
                    throw new ConditionException(ErrorCodes.A0400, msg);
                }
                this.normalizingCondition(nestedConditionObj);

                Set<String> localNestedLabelIds = this.loadNestedLabels(finalLabelId, nestedConditionObj);
                if (!CollectionUtils.isEmpty(localNestedLabelIds)) {
                    nestedLabelIds.addAll(localNestedLabelIds);
                }
            });

            nestedLabelIds.forEach(nestedLabelId -> {
                queue.offer(nestedLabelId);

                graph.addVertex(nestedLabelId);
                graph.addEdge(finalLabelId, nestedLabelId);
            });
        }

        // 获取最长路径
        List<String> longestPath = graph.getLongestPath(Constants.NEGATIVE_ONE_STR);
        if (longestPath.size() > Constants.MAX_NESTED_LABEL_LEVEL) {
            List<String> labelNames = longestPath.stream().map(labelMap::get).collect(Collectors.toList());
            String msg = String.format("标签依赖深度不能超过3层，%s", String.join("->", labelNames));
            throw new ConditionException(ErrorCodes.A0400, msg);
        }
    }

    /**
     * 自动打标签
     */
    @Override
    public ServiceResult<Void> labelMembers(LabelMembersParam param) {
        String orgId = param.getOrgId();
        String batchId = param.getBatchId();

        // 给联系人打标签，每次最多推送Constants.MAX_AUTO_LABEL_BATCH_SIZE个联系人
        List<MemberParam> members = param.getMembers();
        if (members.size() > maxAutoLabelBatchSize) {
            String msg = String.format("每个批次推送的联系人数量不能超过%s个", maxAutoLabelBatchSize);
            return ServiceResult.fail(msg);
        }

        // 记录性能日志
        if (MEMBER_PERFORMANCE_LOG.isInfoEnabled() && PerformanceConfig.LABEL_MEMBER_LOG_ENABLED) {
            MEMBER_PERFORMANCE_LOG.info("【打标签性能监控】开始 orgId: {}, batchId: {}, memberSize: {}, timestamp: {}",
                    orgId, batchId, members.size(), System.currentTimeMillis());
        }

        // 构建给联系人打标签上下文
        LabelMemberContext context = new LabelMemberContext();
        context.setOrgId(orgId);
        context.setBatchId(batchId);
        context.setMemberIds(members.stream().map(MemberParam::getId).collect(Collectors.toList()));

        // 加载标签
        // 将允许自动打标签的标签数据从数据库中加载出来，并组织为层级结构
        if (MEMBER_PERFORMANCE_LOG.isInfoEnabled() && PerformanceConfig.LABEL_MEMBER_LOG_ENABLED) {
            MEMBER_PERFORMANCE_LOG.info("【打标签性能监控】加载标签开始 batchId: {}, timestamp: {}", batchId, System.currentTimeMillis());
        }
        this.loadLabels(context);
        if (MEMBER_PERFORMANCE_LOG.isInfoEnabled() && PerformanceConfig.LABEL_MEMBER_LOG_ENABLED) {
            MEMBER_PERFORMANCE_LOG.info("【打标签性能监控】加载标签结束 batchId: {}, labelSize: {}, timestamp: {}",
                    batchId, context.getLabelMap().size(), System.currentTimeMillis());
        }

        // 预处理自动打标签条件
        if (MEMBER_PERFORMANCE_LOG.isInfoEnabled() && PerformanceConfig.LABEL_MEMBER_LOG_ENABLED) {
            MEMBER_PERFORMANCE_LOG.info("【打标签性能监控】预处理自动打标签条件开始 batchId: {}, timestamp: {}", batchId, System.currentTimeMillis());
        }
        this.processConditions(context);
        if (log.isInfoEnabled()) {
            log.info("【打标签性能监控】预处理自动打标签条件结束 batchId: {}, timestamp: {}",
                    batchId, System.currentTimeMillis());
        }

        // 计算问卷相关的自动打标签条件是否满足打标签条件
        if (MEMBER_PERFORMANCE_LOG.isInfoEnabled() && PerformanceConfig.LABEL_MEMBER_LOG_ENABLED) {
            MEMBER_PERFORMANCE_LOG.info("【打标签性能监控】计算问卷条件开始 batchId: {}, timestamp: {}", batchId, System.currentTimeMillis());
        }
        this.executeSurveyCondition(context);
        // 问卷项目相关的条件使用完毕，清除
        context.getSurveyConditionMap().clear();
        if (MEMBER_PERFORMANCE_LOG.isInfoEnabled() && PerformanceConfig.LABEL_MEMBER_LOG_ENABLED) {
            MEMBER_PERFORMANCE_LOG.info("【打标签性能监控】计算问卷条件结束 batchId: {}, surveyConditionSize: {}, timestamp: {}",
                    batchId, context.getSurveyConditionMap().size(), System.currentTimeMillis());
        }

        // 自动打标签
        if (MEMBER_PERFORMANCE_LOG.isInfoEnabled() && PerformanceConfig.LABEL_MEMBER_LOG_ENABLED) {
            MEMBER_PERFORMANCE_LOG.info("【打标签性能监控】打标签开始 batchId: {}, timestamp: {}", batchId, System.currentTimeMillis());
        }
        this.labelMembers(context, members);
        if (MEMBER_PERFORMANCE_LOG.isInfoEnabled() && PerformanceConfig.LABEL_MEMBER_LOG_ENABLED) {
            MEMBER_PERFORMANCE_LOG.info("【打标签性能监控】打标签结束 batchId: {}, sortedLabelIdSize: {}, timestamp: {}",
                    batchId, context.getSortedLabelIds().size(), System.currentTimeMillis());
        }

        // 保存标签至联系人服务
        if (MEMBER_PERFORMANCE_LOG.isInfoEnabled() && PerformanceConfig.LABEL_MEMBER_LOG_ENABLED) {
            MEMBER_PERFORMANCE_LOG.info("【打标签性能监控】保存标签开始 batchId: {}, timestamp: {}", batchId, System.currentTimeMillis());
        }
        this.saveMemberLabels(context);
        if (MEMBER_PERFORMANCE_LOG.isInfoEnabled() && PerformanceConfig.LABEL_MEMBER_LOG_ENABLED) {
            MEMBER_PERFORMANCE_LOG.info("【打标签性能监控】保存标签结束 batchId: {}, modifiedMemberLabelMap: {}, timestamp: {}",
                    batchId, context.getModifiedMemberLabelMap().size(), System.currentTimeMillis());
        }

        this.updateOrgMemberGroups(param.getOrgId());
        if (MEMBER_PERFORMANCE_LOG.isInfoEnabled() && PerformanceConfig.LABEL_MEMBER_LOG_ENABLED) {
            MEMBER_PERFORMANCE_LOG.info("【打标签性能监控】异步更新联系人分组信息 batchId: {}, modifiedMemberLabelMap: {}, timestamp: {}",
                    batchId, context.getModifiedMemberLabelMap().size(), System.currentTimeMillis());
        }

        if (MEMBER_PERFORMANCE_LOG.isInfoEnabled() && PerformanceConfig.LABEL_MEMBER_LOG_ENABLED) {
            MEMBER_PERFORMANCE_LOG.info("【打标签性能监控】结束 orgId: {}, batchId: {}, memberSize: {}, timestamp: {}",
                    orgId, batchId, members.size(), System.currentTimeMillis());
        }

        // 清理内存
        context.clean();
        param.clean();
        return ServiceResult.success();
    }

    /**
     * 异步更新企业下联系人的分组信息
     * @param orgId 企业id
     * @return 更新结果
     */
    private void updateOrgMemberGroups(String orgId){
        groupService.sendGroupMessages(orgId);
    }

    /**
     * 加载标签列表
     *
     * @param context
     * @return
     */
    private void loadLabels(LabelMemberContext context) {
        String orgId = context.getOrgId();
        List<LabelValueDO> labelValues = labelValueDao.listByOrgIdAndAuto(orgId, Constants.TRUE);
        if (log.isInfoEnabled()) {
            log.info("该组织 {} 标签的数量 {}", orgId, labelValues.size());
        }
        // 根据标签标识对标签值列表进行分组
        // <labelId, labelValues>
        Map<String, List<LabelValueDTO>> labelMap = labelValues.stream()
                .map(LabelValueDTO::convert)
                .collect(Collectors.groupingBy(LabelValueDTO::getLabelId));
        // 将分组后的标签值列表放入上下文中
        context.setLabelMap(labelMap);
    }

    /**
     * 归一化标签值条件
     *
     * @param context
     */
    private void processConditions(LabelMemberContext context) {
        // 标签值层级结构
        // <labelId, List<LabelValueDTO>>
        Map<String, List<LabelValueDTO>> labelMap = context.getLabelMap();

        // 归一化标签值列表中的动态条件
        GraphSorter<String> labelSorter = new GraphSorter<>();
        for (Map.Entry<String, List<LabelValueDTO>> labelMapEntry : labelMap.entrySet()) {
            String labelId = labelMapEntry.getKey();
            List<LabelValueDTO> labelValueDTOs = labelMapEntry.getValue();
            labelSorter.addVertex(labelId);

            for (LabelValueDTO labelValueDTO : labelValueDTOs) {
                String labelValueId = labelValueDTO.getId();
                String condition = labelValueDTO.getCondition();
                JSONObject conditionObj = JsonUtil.tryConvertToJSONObject(condition);
                if (conditionObj == null) {
                    log.error("label value condition convert to json failed, skip label value, labelValueId: {}",
                            labelValueId);
                    continue;
                }

                try {
                    // 归一化标签值中的动态条件
                    this.normalizingCondition(conditionObj);
                    labelValueDTO.setConditionObj(conditionObj);

                    // 获取直接依赖的标签列表
                    Set<String> nestedLabelIds = this.loadNestedLabels(labelId, conditionObj);
                    if (!CollectionUtils.isEmpty(nestedLabelIds)) {
                        nestedLabelIds.stream().filter(Objects::nonNull)
                                .filter(labelMap::containsKey)
                                .forEach(nestedLabelId -> labelSorter.addEdge(nestedLabelId, labelId));
                    }

                    // 加载问卷相关的条件
                    // 将标签值的自动打标签条件中问卷相关的条件截取出来，放入上下文中
                    List<SurveyConditionDTO> surveyConditions = this.loadSurveyConditions(conditionObj);
                    surveyConditions.forEach(surveyCondition ->
                            context.addSurveyCondition(surveyCondition.getConditionId(), surveyCondition));
                } catch (ConditionGrammarException e) {
                    log.error("label value condition grammar error, skip label value, labelValueId: {}",
                            labelValueId, e);
                }
            }
        }

        GraphSortResult<String> labelSortResult = labelSorter.sort();
        if (labelSortResult.hasCircle()) {
            if (log.isInfoEnabled()) {
                log.info("label sort done, skip label in circles, labelSortResult: {}", labelSortResult);
            }
        }
        context.setSortedLabelIds(labelSortResult.getSortedVertexes());
    }

    /**
     * 加载层级
     *
     * @param conditionObj
     */
    private void loadGroups(JSONObject conditionObj) {

    }

    /**
     * 加载依赖的标签
     *
     * @param labelId
     * @param conditionObj
     * @return
     */
    private Set<String> loadNestedLabels(String labelId, JSONObject conditionObj) {
        Map<String, Set<String>> nestedLabelMap = this.loadNestedLabelMap(labelId, conditionObj);
        return nestedLabelMap == null ? Collections.emptySet() : nestedLabelMap.keySet();
    }

    /**
     * 加载依赖的标签
     *
     * @param labelId
     * @param conditionObj
     * @return
     */
    private Map<String, Set<String>> loadNestedLabelMap(String labelId, JSONObject conditionObj) {
        ConditionTraverser traverser = new ConditionTraverser() {
            @Override
            protected void onSimpleCondition(JSONObject simpleCondition, Map<String, Object> contextParams) {
                // 若不是标签条件，直接跳过
                String source = simpleCondition.getString(ConditionConstant.SOURCE);
                if (!StringUtils.equals(source, ConditionConstant.Sources.LABEL)) {
                    return;
                }

                Object parentLabelId = contextParams.get(ConditionConstant.LABEL_ID);
                ConditionProxy conditionProxy = new ConditionProxy(simpleCondition);
                String nestedLabelId = (String) conditionProxy.getRawDetailValue(ConditionConstant.TAG_ID);
                if (StringUtils.isBlank(nestedLabelId)) {
                    throw new ConditionGrammarException("condition.label_id missing");
                }
                if (Objects.equals(parentLabelId, nestedLabelId)) {
                    throw new ConditionGrammarException("condition.label_id is same with parent");
                }

                // 获取标签值标识
                String nestedLabelValueId = null;
                String operator = conditionProxy.getOperator();
                if (StringUtils.equals(operator, ConditionConstant.Operators.EQ) ||
                        StringUtils.equals(operator, ConditionConstant.Operators.NE)) {
                    nestedLabelValueId = conditionProxy.getStringValue(Constants.TRUE);
                }

                Map<String, Set<String>> nestedLabelMap = (Map<String, Set<String>>) contextParams
                        .get(ConditionConstant.LABEL_MAP);
                if (nestedLabelMap == null) {
                    nestedLabelMap = new LinkedHashMap<>();
                }

                Set<String> nestedLabelValueIds = nestedLabelMap.get(nestedLabelId);
                if (nestedLabelValueIds == null) {
                    nestedLabelValueIds = new LinkedHashSet<>();
                }
                if (StringUtils.isNotBlank(nestedLabelValueId)) {
                    nestedLabelValueIds.add(nestedLabelValueId);
                }
                nestedLabelMap.put(nestedLabelId, nestedLabelValueIds);
                contextParams.put(ConditionConstant.LABEL_MAP, nestedLabelMap);
            }
        };

        Map<String, Object> contextParams = new HashMap<>();
        contextParams.put(ConditionConstant.LABEL_ID, labelId);
        traverser.traverse(conditionObj, contextParams);
        return (Map<String, Set<String>>) contextParams.get(ConditionConstant.LABEL_MAP);
    }

    /**
     * 归一化标签值条件
     *
     * @param conditionObj
     */
    private void normalizingCondition(JSONObject conditionObj) {
        // 校验版本号
        int versionValue = conditionObj.getIntValue(ConditionConstant.CONDITION_VERSION);
        ConditionVersionEnum version = EnumUtil.getEnumByIndex(ConditionVersionEnum.class, versionValue);
        if (version == null && versionValue != Constants.ZERO) {
            throw new ConditionGrammarException("normalizing condition failed, unknown condition version");
        }

        // 如果不是版本2，不需要归一化
        if (versionValue != ConditionVersionEnum.VERSION2.getIndex()) {
            return;
        }
        // 版本归一化
        conditionObj.put(ConditionConstant.CONDITION_VERSION, ConditionVersionEnum.VERSION3.getIndex());

        List<JSONObject> filters = (List<JSONObject>) conditionObj.get(ConditionConstant.FILTERS);
        if (CollectionUtils.isEmpty(filters)) {
            throw new ConditionException("condition.filters missing");
        }
        // 自动打标签条件，每个条件组最多包含5个条件或条件组
        if (filters.size() > Constants.MAX_SIBLING_CONDITION_NUM) {
            throw new ConditionException(ErrorCodes.A0400, "每个条件组最多包含5个条件或条件组");
        }

        // 获取问卷相关条件
        JSONObject surveyCondition; // 问卷相关条件
        List<JSONObject> surveyConditions = filters.stream().filter(Objects::nonNull).filter(filter -> {
            String category = filter.getString(ConditionConstant.CATEGORY);
            return StringUtils.equals(category, ConditionCategoryEnum.PROJECT.getName());
        }).collect(Collectors.toList());
        if (surveyConditions.size() > Constants.TWO) { // 超过两个问卷相关条件
            throw new ConditionGrammarException("normalizing condition failed, more than one survey condition found in version 2");
        } else if (surveyConditions.size() == Constants.ONE) { // 包含一个问卷相关条件
            surveyCondition = surveyConditions.get(0);
        } else { // 不包含问卷相关条件
            return;
        }

        // 从问卷相关条件中获取问卷项目标识
        String projectId = surveyCondition.getString(ConditionConstant.PROJECT_ID);
        String projectName = surveyCondition.getString(ConditionConstant.PROJECT_NAME);
        if (StringUtils.isBlank(projectId)) {
            throw new ConditionGrammarException("condition.project_id missing");
        }

        // 问卷条件归一化
        surveyCondition.remove(ConditionConstant.CATEGORY);
        surveyCondition.remove(ConditionConstant.PROJECT_ID);
        surveyCondition.remove(ConditionConstant.PROJECT_NAME);
        conditionObj.put(ConditionConstant.PROJECT_ID, projectId);
        conditionObj.put(ConditionConstant.PROJECT_NAME, projectName);
        ConditionTraverser traverser = new ConditionTraverser() {
            @Override
            protected void onSimpleCondition(JSONObject simpleCondition, Map<String, Object> contextParams) {
                // 补充数据来源字段
                simpleCondition.put(ConditionConstant.SOURCE, ConditionConstant.Sources.SURVEY);
            }
        };
        traverser.traverse(surveyCondition);
    }

    /**
     * 加载问卷相关条件
     *
     * @param conditionObj
     * @return
     */
    private List<SurveyConditionDTO> loadSurveyConditions(JSONObject conditionObj) {
        Queue<JSONObject> queue = new LinkedList<>();
        queue.offer(conditionObj);

        // 获取问卷项目标识
        String projectId = conditionObj.getString(ConditionConstant.PROJECT_ID);

        JSONObject currentCondition;
        List<SurveyConditionDTO> surveyConditions = new ArrayList<>();
        while ((currentCondition = queue.poll()) != null) {
            List<JSONObject> filters = (List<JSONObject>) currentCondition.get(ConditionConstant.FILTERS);
            if (filters != null) {
                if (CollectionUtils.isEmpty(filters)) {
                    throw new ConditionException("condition.filters missing");
                }

                // 自动打标签条件，每个条件组最多包含5个条件或条件组
                if (filters.size() > Constants.MAX_SIBLING_CONDITION_NUM) {
                    throw new ConditionException(ErrorCodes.A0400, "每个条件组最多包含5个条件或条件组");
                }

                filters.forEach(queue::offer);
            } else {
                // 如果不是问卷相关条件，直接跳过
                String source = currentCondition.getString(ConditionConstant.SOURCE);
                if (!StringUtils.equals(source, ConditionConstant.Sources.SURVEY)) {
                    continue;
                }

                // 为当前问卷相关条件存入一个唯一标识，方便根据唯一标识获取当前条件执行结果
                String conditionId;
                if (appConfig.isTestEnv()) {
                    conditionId = currentCondition.getString(ConditionConstant.CONDITION_ID);
                } else {
                    conditionId = ObjectId.get().toHexString();
                    currentCondition.put(ConditionConstant.CONDITION_ID, conditionId);
                }

                SurveyConditionDTO surveyCondition = new SurveyConditionDTO();
                surveyCondition.setConditionId(conditionId);
                surveyCondition.setProjectId(projectId);
                surveyCondition.setCondition(currentCondition.toJSONString());
                surveyConditions.add(surveyCondition);
            }
        }

        if (!CollectionUtils.isEmpty(surveyConditions) && StringUtils.isBlank(projectId)) {
            throw new ConditionGrammarException("condition.project_id missing");
        }
        return surveyConditions;
    }

    /**
     * 解释执行问卷相关条件
     *
     * @param context
     */
    private void executeSurveyCondition(LabelMemberContext context) {
        String batchId = context.getBatchId();
        List<String> memberIds = context.getMemberIds();
        Map<String, SurveyConditionDTO> surveyConditionMap = context.getSurveyConditionMap();

        // 组装问卷条件解释执行参数
        List<ExecuteConditionParam> executeConditionParams =
                new ArrayList<>(REQUEST_SIZE);
        List<ExecuteConditionDTO> result =
                new ArrayList<>(memberIds.size() * surveyConditionMap.size());
        int num = REQUEST_SIZE;
        for (String memberId : memberIds) {
            for (SurveyConditionDTO surveyCondition : surveyConditionMap.values()) {
                String conditionId = surveyCondition.getConditionId();
                String projectId = surveyCondition.getProjectId();
                String condition = surveyCondition.getCondition();

                ExecuteConditionParam executeConditionParam = new ExecuteConditionParam();
                executeConditionParam.setConditionId(conditionId);
                executeConditionParam.setMemberId(memberId);
                executeConditionParam.setOrgId(context.getOrgId());
                executeConditionParam.setProjectId(projectId);
                executeConditionParam.setCondition(condition);
                executeConditionParams.add(executeConditionParam);
                --num;
                if (num <= 0) {
                    String conditionSliceId = IdUtil.uuid();
                    if (log.isInfoEnabled()) {
                        log.info("【打标签性能监控】计算单片问卷条件开始 batchId: {}, conditionSliceId: {}, conditionNum: {}, timestamp: {}",
                                batchId, conditionSliceId, executeConditionParams.size(), System.currentTimeMillis());
                    }

//                    if (log.isInfoEnabled()) {
//                        log.info("计算单片问卷条件临时参数, conditionSliceId: {}, params {}",
//                                conditionSliceId, JSONUtil.tryConvertToJSONString(executeConditionParams));
//                    }

                    // 若计数 <=0 说明已经保存了 REQUEST_SIZE条数据 开始进行请求
                    List<ExecuteConditionDTO> executeConditionDTOS = surveyClient.executeConditions(executeConditionParams);
                    result.addAll(executeConditionDTOS);
                    // 清空
                    executeConditionParams.clear();
                    // 恢复计数
                    num = REQUEST_SIZE;

//                    if (log.isInfoEnabled()) {
//                        log.info("计算单片问卷条件临时结果, conditionSliceId: {}, results {}",
//                                conditionSliceId, JSONUtil.tryConvertToJSONString(executeConditionDTOS));
//                    }

                    if (log.isInfoEnabled()) {
                        log.info("【打标签性能监控】计算单片问卷条件结束 batchId: {}, conditionSliceId: {}, resultNum: {}, timestamp: {}",
                                batchId, conditionSliceId, executeConditionDTOS.size(), System.currentTimeMillis());
                    }
                }
            }
        }
        if (!CollectionUtils.isEmpty(executeConditionParams)) {
            String conditionSliceId = IdUtil.uuid();
            if (log.isInfoEnabled()) {
                log.info("【打标签性能监控】计算单片问卷条件开始 batchId: {}, conditionSliceId: {}, conditionNum: {}, timestamp: {}",
                        batchId, conditionSliceId, executeConditionParams.size(), System.currentTimeMillis());
            }

//            if (log.isInfoEnabled()) {
//                log.info("计算单片问卷条件临时参数, conditionSliceId: {}, params {}",
//                        conditionSliceId, JSONUtil.tryConvertToJSONString(executeConditionParams));
//            }

            // 最后一次 请求
            List<ExecuteConditionDTO> executeConditionDTOS = surveyClient.executeConditions(executeConditionParams);
            result.addAll(executeConditionDTOS);
            // 清空
            executeConditionParams.clear();

//            if (log.isInfoEnabled()) {
//                log.info("计算单片问卷条件临时结果, conditionSliceId: {}, results {}",
//                        conditionSliceId, JSONUtil.tryConvertToJSONString(executeConditionDTOS));
//            }

            if (log.isInfoEnabled()) {
                log.info("【打标签性能监控】计算单片问卷条件结束 batchId: {}, conditionSliceId: {}, resultNum: {}, timestamp: {}",
                        batchId, conditionSliceId, executeConditionDTOS.size(), System.currentTimeMillis());
            }
        }
        // 问卷条件解释执行结果格式化，并加入上线文中
        // <conditionId:memberId, result>
        // result 1-匹配、2-不匹配、3-没有答卷
        // List<ExecuteConditionDTO> executeConditionDTOS = surveyClient.executeConditions(executeConditionParams);
        Function<ExecuteConditionDTO, String> keyGenerateFunction = item ->
                String.format(ConditionConstant.SURVEY_CONDITION_RESULT_KEY_TEMPLATE, item.getConditionId(),
                        item.getMemberId());
        Map<String, Integer> surveyConditionResult = result.stream()
                .collect(Collectors.toMap(keyGenerateFunction, ExecuteConditionDTO::getMatch));
        context.setSurveyConditionResult(surveyConditionResult);
    }

    /**
     * 给联系人打标签
     *
     * @param context
     * @param members
     */
    private void labelMembers(LabelMemberContext context, List<MemberParam> members) {
        Map<String, List<LabelValueDTO>> labelMap = context.getLabelMap();
        // 被修改过的联系人标签
        Map<String, List<LabelValueIdParam>> modifiedMemberLabelMap = new HashMap<>(members.size());
        // 遍历联系人，为联系人打上标签
        for (MemberParam member : members) {
            String memberId = member.getId();
            // 获取联系人旧标签
            List<LabelValueIdParam> oldValueIds = member.getLabelValueIds();
            // 联系人信息
            JSONObject params = JsonUtil.tryConvertToJSONObject(member);
            if (params == null) {
                log.error("member convert to json failed, skip member, memberId: {}", memberId);
                continue;
            }

            // 联系人新标签映射集合。这里初始化为旧标签值集合，通过添加、删除更新联系人标签
            List<LabelValueIdParam> newValueIds = modifiedMemberLabelMap.get(memberId);
            if (newValueIds == null) {
                newValueIds = oldValueIds == null ? new ArrayList<>() : oldValueIds;
            }

            // 遍历企业下所有标签
            label:
            for (String labelId : context.getSortedLabelIds()) {
                List<LabelValueDTO> labelValues = labelMap.get(labelId);

                LabelValueIdParam addValueId = null;
                List<LabelValueIdParam> removeValueIds = new ArrayList<>(labelValues.size());
                // 遍历标签下所有标签值
                for (LabelValueDTO labelValue : labelValues) {
                    String rawValueId = labelValue.getId();
                    // 获取标签值条件
                    JSONObject conditionObj = labelValue.getConditionObj();
                    if (conditionObj == null) {
                        log.error("condition convert to json failed, skip whole label, labelValueId: {}", rawValueId);
                        continue label;
                    }

                    // 如果存在则已有满足的标签值，这里不再校验，因为只需要拿到第一个满足的标签值
                    if (addValueId == null) {
                        try {
                            // 校验联系人是否满足当前标签值的条件
                            String projectId = conditionObj.getString(ConditionConstant.PROJECT_ID);
                            boolean matched = this.calcCompoundCondition(context, conditionObj, params, projectId,
                                    newValueIds);
                            if (matched) {
                                // 满足则赋值addValueId
                                addValueId = LabelValueIdParam.of(rawValueId, labelValue);
                            }
                        } catch (Exception e) {
                            // 参数异常，直接跳过该标签
                            log.error("condition grammar error, skip whole label, labelValueId: {}, memberId: {}",
                                    rawValueId, memberId, e);
                            continue label;
                        }
                    }
                    // 当前标签下所有的标签值
                    removeValueIds.add(LabelValueIdParam.of(rawValueId, labelValue));
                }

                // 这里的newValueIds实际上是联系人旧标签值集合
                List<LabelValueIdParam> finalNewValueIds = newValueIds;
                // 旧标签值集合中存在与当前标签下所有的标签值存在交集，那么旧标签值可能需要删除
                boolean needRemove = removeValueIds.stream().anyMatch(finalNewValueIds::contains);
                if (addValueId != null || needRemove) {
                    // 移除所有该标签下所有标签值，newValueIds如果一开始取空集合，直接插入新标签值即可
                    newValueIds.removeAll(removeValueIds);
                    // 如果满足条件，添加新标签值
                    if (addValueId != null) {
                        newValueIds.add(addValueId);
                    }
                    // 保存联系人新标签
                    modifiedMemberLabelMap.put(memberId, newValueIds);
                }
            }
        }
        // 将修改过的标签，加入上下文
        context.setModifiedMemberLabelMap(modifiedMemberLabelMap);
    }

    /**
     * 计算条件组
     *
     * @param context
     * @param condition
     * @param params
     * @param projectId
     * @param labels
     * @return
     */
    private boolean calcCompoundCondition(LabelMemberContext context, JSONObject condition, JSONObject params,
                                       String projectId, List<LabelValueIdParam> labels) {
        // 计算条件组
        List<JSONObject> filters = (List<JSONObject>) condition.get(ConditionConstant.FILTERS);
        if (filters != null) {
            // 自动打标签条件，每个条件组最多包含5个条件或条件组
            if (filters.size() > Constants.MAX_SIBLING_CONDITION_NUM) {
                throw new ConditionGrammarException("每个条件组最多包含5个条件或条件组");
            }

            String rule = condition.getString(ConditionConstant.RULE);
            if (rule == null) {
                rule = ConditionConstant.RuleOperators.OR;
            }

            // 条件组与、或关系计算
            List<Boolean> filterMatches = filters.stream()
                    .map(filter -> calcCompoundCondition(context, filter, params, projectId, labels))
                    .collect(Collectors.toList());
            switch (rule) {
                case ConditionConstant.RuleOperators.AND:
                    return filterMatches.stream().allMatch(matched -> matched);
                case ConditionConstant.RuleOperators.OR:
                    return filterMatches.stream().anyMatch(matched -> matched);
                default:
                    throw new ConditionGrammarException(String.format("condition.rule unsupported, rule: %s", rule));
            }
        } else {
            return this.calcSimpleCondition(context, condition, params, projectId, labels);
        }
    }

    /**
     * 计算简单条件
     *
     * @param context
     * @param condition
     * @param params
     * @param projectId
     * @return
     */
    private boolean calcSimpleCondition(LabelMemberContext context, JSONObject condition, JSONObject params,
                                          String projectId, List<LabelValueIdParam> labels) {
        Map<String, Integer> surveyConditionResult = context.getSurveyConditionResult();
        String memberId = params.getString(ConditionConstant.ID);

        String source = condition.getString(ConditionConstant.SOURCE);
        if (StringUtils.equals(source, ConditionConstant.Sources.SURVEY)) { // 计算问卷最小条件单元
            if (StringUtils.isBlank(projectId)) {
                throw new ConditionGrammarException("condition.project_id missing");
            }

            String conditionId = condition.getString(ConditionConstant.CONDITION_ID);
            if (StringUtils.isBlank(conditionId)) {
                throw new ConditionGrammarException("condition.__condition_id__ missing");
            }

            // 问卷条件结果解析
            String surveyConditionKey = String.format(ConditionConstant.SURVEY_CONDITION_RESULT_KEY_TEMPLATE,
                    conditionId, memberId);
            Integer match = surveyConditionResult.get(surveyConditionKey);
            if (match == null) {
                throw new ConditionGrammarException("survey condition result missing");
            }
            return Objects.equals(match, MatchEnum.MATCH.getIndex());
        } else if(StringUtils.equals(source, ConditionConstant.Sources.LABEL)) {
            ConditionProxy conditionProxy = new ConditionProxy(condition);
            String operator = conditionProxy.getOperator();
            Object labelValueId = conditionProxy.getValue();
            Object labelId = conditionProxy.getRawDetailValue(ConditionConstant.TAG_ID);
            if (labels == null) {
                labels = Collections.emptyList();
            }

            // 标签和标签值匹配器
            Predicate<LabelValueIdParam> labelMatcher = label ->  Objects.equals(labelId, label.getLabelId());
            Predicate<LabelValueIdParam> labelValueMatcher = label -> Objects.equals(labelValueId, label.getId())
                    && Objects.equals(labelId, label.getLabelId());

            Stream<LabelValueIdParam> labelStream = labels.stream().filter(Objects::nonNull);
            if (StringUtils.equals(operator, ConditionConstant.Operators.EQ)) {
                return labelStream.anyMatch(labelValueMatcher);
            } else if (StringUtils.equals(operator, ConditionConstant.Operators.NE)) {
                return labelStream.noneMatch(labelValueMatcher);
            } else if (StringUtils.equals(operator, ConditionConstant.Operators.NEXISTS)) {
                return labelStream.noneMatch(labelMatcher);
            } else if (StringUtils.equals(operator, ConditionConstant.Operators.EXISTS)) {
                return labelStream.anyMatch(labelMatcher);
            } else {
                String msg = String.format("condition.operator unsupported, operator: %s", operator);
                throw new ConditionGrammarException(msg);
            }
        } else { // 计算其它最小条件单
            ConditionProxy conditionProxy = new ConditionProxy(condition);
            String operator = conditionProxy.getOperator();
            if (ConditionConstant.Operators.INCLUDE.equals(operator)) {
                // 层级记一下
                List<Object> values = conditionProxy.listValues();
                if (CollectionUtils.isEmpty(values) || values.size() < 1) {
                    throw new ConditionException(String.format("condition.value %s illegal", values));
                }

                Object endValue = values.get(values.size() - 1);
                if (endValue == null) {
                    String msg = String.format("condition.value missing for level, endValue: %s", endValue);
                    throw new ConditionException(msg);
                }
                String fieldName = conditionProxy.getName();
                String param = params.getString(fieldName);
                if (StrUtil.isEmpty(param)) {
                    return false;
                }
                List<String> storeIds = memberUserGroupService.listByParentIn(String.valueOf(endValue));
                return storeIds.contains(param);

            }
            ConditionCalculator calculator = ConditionCalculatorFactory.newCalculator(context.getGroupMap(), condition, params);
            return calculator.calculate();
        }
    }

    /**
     * 保存标签
     *
     * @param context
     */
    private void saveMemberLabels(LabelMemberContext context) {
        Map<String, List<LabelValueIdParam>> modifiedMemberLabelMap = context.getModifiedMemberLabelMap();
        memberDao.saveLabels(modifiedMemberLabelMap);
    }
}
